package com.cloudbroker.openapi.mobile.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cloudbroker.bcs.common.configure.ConfigUtil;
import com.cloudbroker.bcs.common.util.IOUtil;
import com.cloudbroker.bcs.common.util.StringUtil;
import com.cloudbroker.bcs.platform.dav.bizapi.constants.HSBCPSFields;
import com.cloudbroker.bcs.platform.dav.bizapi.constants.IFSFunctionIdsNew;

public class HttpUtil {
    private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class);

	private static final CloseableHttpClient httpClient;
    private static final RequestConfig requestConfig;
	public static final String CHARSET = "UTF-8";
    public static final  int MAX_TOTAL_CONNECTIONS = 2000;//连接池最大并发连接数
    public static final  int MAX_ROUTE_CONNECTIONS = 2000;//单路由最大并发数
    public static final  int CONNECT_TIMEOUT = 9000;
    public static final  int SOCKET_TIMEOUT = 6000;

	static {
		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(MAX_TOTAL_CONNECTIONS);
		cm.setDefaultMaxPerRoute(MAX_ROUTE_CONNECTIONS);
		httpClient = HttpClients.custom().setConnectionManager(cm).build();
        requestConfig = RequestConfig.custom().setSocketTimeout(SOCKET_TIMEOUT).setConnectTimeout(CONNECT_TIMEOUT).build();
    }

	public static String doGet(String url, Map<String, Object> params) {
		return doGet(url, params, CHARSET);
	}

	public static String doPost(String url, Map<String, String> map) {
		return doPost(url, map, CHARSET);
	}

	/**
	 * HTTP Get 获取内容
	 * 
	 * @param url
	 *            请求的url地址 ?之前的地址
	 * @param params
	 *            请求的参数
	 * @param charset
	 *            编码格式
	 * @return 页面内容
	 */
	public static String doGet(String url, Map<String, Object> params, String charset) {
		CloseableHttpResponse response = null;
		if (StringUtils.isBlank(url)) {
			return null;
		}
        HttpGet httpGet = null;
        try {
			if (params != null && !params.isEmpty()) {
				List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
				for (Map.Entry<String, Object> entry : params.entrySet()) {
					String value = (String) entry.getValue();
					if (value != null) {
						pairs.add(new BasicNameValuePair(entry.getKey(), value));
					}
				}
				url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
			}
			httpGet = new HttpGet(url);
            httpGet.setConfig(requestConfig);
			response = httpClient.execute(httpGet);
			return acquireResult(response , httpGet);
		} catch (Exception e) {
			logger.error("do get error " , e);
		} finally {
			IOUtil.close(response);
			if(null != httpGet){
			    httpGet.releaseConnection();
			}
		}
		return null;
	}

	/**
	 * HTTP Post 获取内容
	 * 
	 * @param url
	 *            请求的url地址 ?之前的地址
	 * @param map
	 *            请求的参数
	 * @param charset
	 *            编码格式
	 * @return 页面内容
	 */
	public static String doPost(String url, Map<String, String> map, String charset) {
		CloseableHttpResponse response = null;
		if (StringUtils.isBlank(url)) {
			return null;
		}
        HttpPost httpPost = null;
        try {
			List<NameValuePair> pairs = null;
			if (map != null && !map.isEmpty()) {
				pairs = new ArrayList<NameValuePair>(map.size());
				for (Map.Entry<String, String> entry : map.entrySet()) {
					String value = (String) entry.getValue();
					if (value != null) {
						pairs.add(new BasicNameValuePair(entry.getKey(), value));
					}
				}
			}
            httpPost = new HttpPost(url);
            httpPost.setConfig(requestConfig);
			if (pairs != null && pairs.size() > 0) {
				httpPost.setEntity(new UrlEncodedFormEntity(pairs, CHARSET));
			}
			long startTime = System.currentTimeMillis();
			response = httpClient.execute(httpPost);
			long endTime = System.currentTimeMillis();
			logger.error(url + " spend time " + (endTime - startTime) + " millis");
			return acquireResult(response,httpPost);
		} catch (Exception e) {
			logger.error("do post error " , e);
		} finally {
			IOUtil.close(response);
			if(null != httpPost){
                httpPost.releaseConnection();
            }
		}
		return null;
	}

	/**
	 * 通过HttpClient的post请求 上传文件
	 *
	 * @param key file文件的参数名
	 * @param file 待上传的文件
	 * @param url 文件上传的url
	 *
	 * @return String 服务器返回json字符串
	 * */
	public static String doPost(String key , File file , String url) {
		CloseableHttpResponse response = null;
		if (StringUtils.isBlank(url)) {
			return null;
		}
        HttpPost httppost = null;
        try {
			httppost = new HttpPost(url);
            httppost.setConfig(requestConfig);
			MultipartEntityBuilder builder = MultipartEntityBuilder.create();
			builder.addBinaryBody(key , file);
			httppost.setEntity(builder.build());
			response = httpClient.execute(httppost);
			return acquireResult(response , httppost);
		} catch (Exception e) {
			logger.error("do post error " , e);
		} finally {
			IOUtil.close(response);
			if(null != httppost){
			    httppost.releaseConnection();
            }
		}
		return null;
	}

	/**
	 *	通过HttpClient的get请求下载文件
	 *
	 * 	@param url 文件下载的指定url
	 *
	 * 	@return InputStream 文件流
	 * 		如果未取到文件,则InputStream为null
	 * */
	private static InputStream doGetDownload(String url) {
		CloseableHttpResponse response = null;
		InputStream ips = null;
		if (StringUtils.isBlank(url)) {
			return null;
		}
        HttpGet httpGet = null;
        try {
			httpGet = new HttpGet(url);
            httpGet.setConfig(requestConfig);
			response = httpClient.execute(httpGet);
			ips = response.getEntity().getContent();
			String base64 = "";
			//通过base64复制流,以做到防止response关闭时把流关闭
			if( (base64 = IOUtil.streamToBase64String(ips)).length() != 0 ) {
				ips = IOUtil.base64StringToStream(base64);
			} else {
				return null;
			}
		} catch (Exception e) {
			logger.error("do post error " , e);
		} finally {
			IOUtil.close(response);
			if(null != httpGet){
			    httpGet.releaseConnection();
            }
		}
		return ips;
	}

	/***
	 * 获取Http Get/Post请求中返回的数据
	 * @param response	服务器返回response
	 * @param requestBase HttpGet/HttpPost 对象
	 *
	 * @return String 服务器返回数据
	 * */
	private static String acquireResult(CloseableHttpResponse response , HttpRequestBase requestBase) throws IOException {
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK) {
			requestBase.abort();
			throw new RuntimeException("HttpClient,error status code :" + statusCode);
		}
		HttpEntity entity = response.getEntity();
		String result = null;
		if (entity != null) {
			result = EntityUtils.toString(entity, "utf-8");
		}
		EntityUtils.consume(entity);
		return result;
	}

	/**
	 * 根据ConfigUtil获取访问Uag请求的url前缀
	 * */
	private static String getFunctionUrlPrefix() {
		String url = ConfigUtil.get("interface.uag.addr","http://127.0.0.1:21100/hsbc_operate/");
		if (!url.endsWith("/")) {
			url = url + "/";
		}
		return url;
	}

	/**
	 * 使用HttpClient的post请求调用中台功能号
	 *
	 * @param functionId 中台功能号
	 * @param map 请求体内容
	 *
	 * @return 服务器返回内容
	 * */
	public static String doPostFunc(String functionId, Map<String, String> map) {
		String url = getFunctionUrlPrefix();
		url += functionId;
		return doPost(url, map);
	}

	/**
	 * 调用中台默认下载文件的功能接口进行文件下载
	 *
	 * @param key 下载文件名
	 *
	 * @return InputStream 下载的文件流
	 * */
	public static InputStream doDownloadFunc(String key) {
		return doDownloadFunc(null , key);
	}

	/**
	 * 调用中台指定的下载文件的功能接口进行文件下载
	 *
	 * @param functionId 中台指定的功能号
	 * @param key 下载文件名
	 *
	 * @return InputStream 下载的文件流
	 * */
	private static InputStream doDownloadFunc(String functionId, String key) {
		if(StringUtil.isBlank(functionId) ) {
			functionId = IFSFunctionIdsNew.IFSCommonFuncIds.FUNC_DOWNLOAD_FILE;
		}
		String url = getFunctionUrlPrefix();
		url = url + "download/" + functionId + "/" + key;
		return doGetDownload(url);
	}

	/**
	 * 调用中台默认的接口进行文件上传
	 *
	 * @param file 待上传文件
	 * @param key 待上传文件的键值
	 *
	 * @return String 服务器返回内容
	 * */
	public static String doPostUploadFunc(File file , String key) {
		return doPostUploadFunc(null , file , key);
	}

	/**
	 * 调用中台指定的上传文件的功能接口进行文件上传
	 *
	 * @param functionId 中台指定的功能号
	 * @param file 待上传文件
	 * @param key 待上传文件的键值
	 *
	 * @return String 服务器返回内容
	 * */
	public static String doPostUploadFunc(String functionId, File file, String key) {
		if(StringUtil.isBlank(functionId) ) {
			functionId = IFSFunctionIdsNew.IFSCommonFuncIds.FUNC_UPLOAD_FILE;
		}
		String url = getFunctionUrlPrefix();
		url = url + "upload/" + file.length() + "/" + key + "/" + functionId;
		return doPost(HSBCPSFields.FILE , file , url);
	}
}